{
 "nbformat": 4,
 "nbformat_minor": 0,
 "metadata": {
  "colab": {
   "name": "handwritten_digit_recognition_CPU.ipynb",
   "version": "0.3.2",
   "provenance": [],
   "collapsed_sections": []
  },
  "kernelspec": {
   "name": "python3",
   "language": "python",
   "display_name": "Python 3 (ipykernel)"
  }
 },
 "cells": [
  {
   "metadata": {
    "id": "MHvuWIUHdIpt",
    "colab_type": "text"
   },
   "cell_type": "markdown",
   "source": [
    "# Handwritten Digit Recognition\n",
    "- Author = Abdelrahman Mohamed\n",
    "- Dataset = MNIST\n",
    "- [Article Link](https://blog.machinfy.com/wp-admin/post.php?post=311)\n",
    "- Frameworks = PyTorch"
   ]
  },
  {
   "metadata": {
    "id": "oGjRmijsaXJ3",
    "colab_type": "text"
   },
   "cell_type": "markdown",
   "source": [
    "### Necessary Imports"
   ]
  },
  {
   "metadata": {
    "id": "TOyGrPT5ASDc",
    "colab_type": "code",
    "colab": {},
    "ExecuteTime": {
     "end_time": "2024-11-26T14:18:51.019453600Z",
     "start_time": "2024-11-26T14:18:51.013530600Z"
    }
   },
   "cell_type": "code",
   "source": [
    "#Scientific computing \n",
    "import numpy as np\n",
    "\n",
    "#Pytorch packages\n",
    "import torch\n",
    "from torch import nn\n",
    "import torch.optim as optim\n",
    "import torchvision\n",
    "from torchvision import datasets, transforms\n",
    "\n",
    "\n",
    "#Visulization\n",
    "import matplotlib.pyplot as plt\n",
    "\n",
    "#Others\n",
    "import time\n",
    "import copy"
   ],
   "execution_count": 2,
   "outputs": []
  },
  {
   "metadata": {
    "id": "uLdtrS4zaeEs",
    "colab_type": "text"
   },
   "cell_type": "markdown",
   "source": [
    "### Download The Dataset & Define The Transforms"
   ]
  },
  {
   "metadata": {
    "id": "sZD2NGz2Ak6w",
    "colab_type": "code",
    "colab": {
     "base_uri": "https://localhost:8080/",
     "height": 119
    },
    "outputId": "74eec0da-d867-406b-be2c-4013a2162bf1",
    "ExecuteTime": {
     "end_time": "2024-11-26T14:19:57.754105500Z",
     "start_time": "2024-11-26T14:18:53.532813300Z"
    }
   },
   "cell_type": "code",
   "source": [
    "# Define a transform to normalize the data\n",
    "transform = transforms.Compose([transforms.ToTensor(),\n",
    "                              transforms.Normalize((0.5,), (0.5,)),\n",
    "                              ])\n",
    "\n",
    "# Download and load the training data\n",
    "trainset = datasets.MNIST('data/', download=True, train=True, transform=transform)\n",
    "valset = datasets.MNIST('data/', download=True, train=False, transform=transform)\n",
    "\n",
    "trainloader = torch.utils.data.DataLoader(trainset, batch_size=64, shuffle=True)\n",
    "valloader = torch.utils.data.DataLoader(valset, batch_size=64, shuffle=True)\n",
    "\n",
    "class_names = trainset.classes\n",
    "dataset_sizes = {'train':len(trainset), 'val':len(valset)}\n",
    "dataloaders  = {'train':trainloader, 'val':valloader}\n",
    "device = torch.device(\"cuda:0\" if torch.cuda.is_available() else \"cpu\")"
   ],
   "execution_count": 3,
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Downloading http://yann.lecun.com/exdb/mnist/train-images-idx3-ubyte.gz\n",
      "Failed to download (trying next):\n",
      "HTTP Error 403: Forbidden\n",
      "\n",
      "Downloading https://ossci-datasets.s3.amazonaws.com/mnist/train-images-idx3-ubyte.gz\n",
      "Downloading https://ossci-datasets.s3.amazonaws.com/mnist/train-images-idx3-ubyte.gz to data/MNIST\\raw\\train-images-idx3-ubyte.gz\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "100.0%\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Extracting data/MNIST\\raw\\train-images-idx3-ubyte.gz to data/MNIST\\raw\n",
      "\n",
      "Downloading http://yann.lecun.com/exdb/mnist/train-labels-idx1-ubyte.gz\n",
      "Failed to download (trying next):\n",
      "HTTP Error 403: Forbidden\n",
      "\n",
      "Downloading https://ossci-datasets.s3.amazonaws.com/mnist/train-labels-idx1-ubyte.gz\n",
      "Downloading https://ossci-datasets.s3.amazonaws.com/mnist/train-labels-idx1-ubyte.gz to data/MNIST\\raw\\train-labels-idx1-ubyte.gz\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "100.0%\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Extracting data/MNIST\\raw\\train-labels-idx1-ubyte.gz to data/MNIST\\raw\n",
      "\n",
      "Downloading http://yann.lecun.com/exdb/mnist/t10k-images-idx3-ubyte.gz\n",
      "Failed to download (trying next):\n",
      "HTTP Error 403: Forbidden\n",
      "\n",
      "Downloading https://ossci-datasets.s3.amazonaws.com/mnist/t10k-images-idx3-ubyte.gz\n",
      "Downloading https://ossci-datasets.s3.amazonaws.com/mnist/t10k-images-idx3-ubyte.gz to data/MNIST\\raw\\t10k-images-idx3-ubyte.gz\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "100.0%\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Extracting data/MNIST\\raw\\t10k-images-idx3-ubyte.gz to data/MNIST\\raw\n",
      "\n",
      "Downloading http://yann.lecun.com/exdb/mnist/t10k-labels-idx1-ubyte.gz\n",
      "Failed to download (trying next):\n",
      "HTTP Error 403: Forbidden\n",
      "\n",
      "Downloading https://ossci-datasets.s3.amazonaws.com/mnist/t10k-labels-idx1-ubyte.gz\n",
      "Downloading https://ossci-datasets.s3.amazonaws.com/mnist/t10k-labels-idx1-ubyte.gz to data/MNIST\\raw\\t10k-labels-idx1-ubyte.gz\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "100.0%"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Extracting data/MNIST\\raw\\t10k-labels-idx1-ubyte.gz to data/MNIST\\raw\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\n"
     ]
    }
   ]
  },
  {
   "metadata": {
    "id": "GcAfrn2falkK",
    "colab_type": "text"
   },
   "cell_type": "markdown",
   "source": [
    "### Exploring The Data"
   ]
  },
  {
   "metadata": {
    "id": "xOjlOyjcCezX",
    "colab_type": "code",
    "outputId": "fde25724-ea30-46f6-cf0f-4a7807c2ee0e",
    "colab": {
     "base_uri": "https://localhost:8080/",
     "height": 68
    },
    "ExecuteTime": {
     "end_time": "2024-11-26T14:23:06.065582200Z",
     "start_time": "2024-11-26T14:23:06.028650200Z"
    }
   },
   "cell_type": "code",
   "source": [
    "dataiter = iter(trainloader)\n",
    "# images, labels = dataiter.next()\n",
    "images, labels = next(dataiter)\n",
    "\n",
    "print(type(images))\n",
    "print(images.shape)\n",
    "print(labels.shape)"
   ],
   "execution_count": 5,
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<class 'torch.Tensor'>\n",
      "torch.Size([64, 1, 28, 28])\n",
      "torch.Size([64])\n"
     ]
    }
   ]
  },
  {
   "metadata": {
    "id": "EuBvOWmGDHOq",
    "colab_type": "code",
    "outputId": "127e0264-be67-4f12-b03f-dac28b7280af",
    "colab": {
     "base_uri": "https://localhost:8080/",
     "height": 265
    },
    "ExecuteTime": {
     "end_time": "2024-11-26T14:23:12.300192700Z",
     "start_time": "2024-11-26T14:23:12.171538100Z"
    }
   },
   "cell_type": "code",
   "source": [
    "plt.imshow(images[0].numpy().squeeze(), cmap='gray_r');"
   ],
   "execution_count": 6,
   "outputs": [
    {
     "data": {
      "text/plain": "<Figure size 640x480 with 1 Axes>",
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAAaAAAAGdCAYAAABU0qcqAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjcuNSwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/xnp5ZAAAACXBIWXMAAA9hAAAPYQGoP6dpAAAbB0lEQVR4nO3df2zU9R3H8dfx6wRtr5baXk8KFhSYAjVj0HUqw9FQuoSAkgX8kYBxEKCYIXOaLirCtnTDxBldh8kyYSbiDxKBaDYyLLZMLRhQRgizoU23ltGWydJeKbYw+tkfjbcdtML3uOu7V56P5JvYu++n37ff3fr0y12/+JxzTgAA9LMh1gMAAK5NBAgAYIIAAQBMECAAgAkCBAAwQYAAACYIEADABAECAJgYZj3Axbq7u3Xy5EmlpKTI5/NZjwMA8Mg5p/b2doVCIQ0Z0vd1zoAL0MmTJ5WTk2M9BgDgKjU2NmrMmDF9Pj/gApSSkiKpZ/DU1FTjaQAAXoXDYeXk5ER+nvclYQEqLy/X888/r+bmZuXl5enll1/WzJkzL7vuqz92S01NJUAAkMQu9zZKQj6E8NZbb2ndunVav369Pv30U+Xl5amoqEinTp1KxOEAAEkoIQF64YUXtHz5cj3yyCO6/fbb9corr2jUqFF69dVXE3E4AEASinuAzp07p0OHDqmwsPB/BxkyRIWFhaqurr5k/66uLoXD4agNADD4xT1AX3zxhS5cuKCsrKyox7OystTc3HzJ/mVlZQoEApGNT8ABwLXB/BdRS0tL1dbWFtkaGxutRwIA9IO4fwouIyNDQ4cOVUtLS9TjLS0tCgaDl+zv9/vl9/vjPQYAYICL+xXQiBEjNH36dFVUVEQe6+7uVkVFhQoKCuJ9OABAkkrI7wGtW7dOS5cu1be+9S3NnDlTL774ojo6OvTII48k4nAAgCSUkAAtXrxY//rXv/Tss8+qublZd955p3bv3n3JBxMAANcun3POWQ/x/8LhsAKBgNra2rgTAgAkoSv9OW7+KTgAwLWJAAEATBAgAIAJAgQAMEGAAAAmCBAAwAQBAgCYIEAAABMECABgggABAEwQIACACQIEADBBgAAAJggQAMAEAQIAmCBAAAATBAgAYIIAAQBMECAAgAkCBAAwQYAAACYIEADABAECAJggQAAAEwQIAGCCAAEATBAgAIAJAgQAMEGAAAAmCBAAwAQBAgCYIEAAABMECABgggABAEwQIACACQIEADBBgAAAJggQAMAEAQIAmCBAAAATBAgAYIIAAQBMECAAgAkCBAAwQYAAACYIEADABAECAJggQAAAEwQIAGCCAAEATBAgAIAJAgQAMDHMegAkr3/+85+e19x8880JmAR9OXfuXEzrFi9e7HmN3+/3vOb111/3vGbo0KGe12Bg4goIAGCCAAEATMQ9QM8995x8Pl/UNnny5HgfBgCQ5BLyHtAdd9yh999//38HGcZbTQCAaAkpw7BhwxQMBhPxrQEAg0RC3gM6fvy4QqGQxo8fr4ceekgNDQ197tvV1aVwOBy1AQAGv7gHKD8/X1u3btXu3bu1efNm1dfX65577lF7e3uv+5eVlSkQCES2nJyceI8EABiA4h6g4uJi/eAHP9C0adNUVFSkP/7xj2ptbdXbb7/d6/6lpaVqa2uLbI2NjfEeCQAwACX80wFpaWmaOHGiamtre33e7/fH9AtsAIDklvDfAzpz5ozq6uqUnZ2d6EMBAJJI3AP0xBNPqKqqSn//+9/18ccf67777tPQoUP1wAMPxPtQAIAkFvc/gjtx4oQeeOABnT59WjfddJPuvvtu7d+/XzfddFO8DwUASGJxD9Cbb74Z72+JAWrLli2e1+zdu7df1qDHmTNnYlq3c+dOz2vuvPNOz2ucc57XYPDgXnAAABMECABgggABAEwQIACACQIEADBBgAAAJggQAMAEAQIAmCBAAAATBAgAYIIAAQBMECAAgImE/4V0GLy6u7s9r/noo488r/nrX//qeU1eXp7nNYPRv//973471i233OJ5zbBh/Ai6lnEFBAAwQYAAACYIEADABAECAJggQAAAEwQIAGCCAAEATBAgAIAJAgQAMEGAAAAmCBAAwAQBAgCYIEAAABPcihYxa29v97zmP//5j+c1Z8+e9bwGPbZv3x7TOp/P53nNk08+GdOxcO3iCggAYIIAAQBMECAAgAkCBAAwQYAAACYIEADABAECAJggQAAAEwQIAGCCAAEATBAgAIAJAgQAMMHNSBGzd9991/Oa1NRUz2tGjx7tec1g1NTU5HnNL37xi5iOdccdd3heU1BQENOxcO3iCggAYIIAAQBMECAAgAkCBAAwQYAAACYIEADABAECAJggQAAAEwQIAGCCAAEATBAgAIAJAgQAMMHNSKHPP/88pnUNDQ2e12zatMnzmokTJ3peMxidPXvW85qOjo6YjvXUU0/FtA7wgisgAIAJAgQAMOE5QPv27dP8+fMVCoXk8/m0c+fOqOedc3r22WeVnZ2tkSNHqrCwUMePH4/XvACAQcJzgDo6OpSXl6fy8vJen9+0aZNeeuklvfLKKzpw4ICuv/56FRUVqbOz86qHBQAMHp4/hFBcXKzi4uJen3PO6cUXX9TTTz+tBQsWSJJee+01ZWVlaefOnVqyZMnVTQsAGDTi+h5QfX29mpubVVhYGHksEAgoPz9f1dXVva7p6upSOByO2gAAg19cA9Tc3CxJysrKino8Kysr8tzFysrKFAgEIltOTk48RwIADFDmn4IrLS1VW1tbZGtsbLQeCQDQD+IaoGAwKElqaWmJerylpSXy3MX8fr9SU1OjNgDA4BfXAOXm5ioYDKqioiLyWDgc1oEDB1RQUBDPQwEAkpznT8GdOXNGtbW1ka/r6+t1+PBhpaena+zYsVq7dq1+/vOf67bbblNubq6eeeYZhUIhLVy4MJ5zAwCSnOcAHTx4UPfee2/k63Xr1kmSli5dqq1bt+rJJ59UR0eHVqxYodbWVt19993avXu3rrvuuvhNDQBIep4DNHv2bDnn+nze5/Np48aN2rhx41UNhv7zu9/9LqZ1X375pec1+fn5MR0L0ltvveV5TVpaWkzHevjhh2NaB3hh/ik4AMC1iQABAEwQIACACQIEADBBgAAAJggQAMAEAQIAmCBAAAATBAgAYIIAAQBMECAAgAkCBAAwQYAAACY83w0bg09TU5P1CLgC1dXV1iMAccUVEADABAECAJggQAAAEwQIAGCCAAEATBAgAIAJAgQAMEGAAAAmCBAAwAQBAgCYIEAAABMECABggpuRQpWVlTGty8jI8Lxm7NixMR0LUn19vfUISevYsWMxrbv99tvjPAn+H1dAAAATBAgAYIIAAQBMECAAgAkCBAAwQYAAACYIEADABAECAJggQAAAEwQIAGCCAAEATBAgAIAJbkaKmI0cOdLzmpSUlARMknyam5s9r2lpaUnAJL2L5can6enpnte0t7d7XrN69WrPa/bs2eN5Tazr7r777piOdS3iCggAYIIAAQBMECAAgAkCBAAwQYAAACYIEADABAECAJggQAAAEwQIAGCCAAEATBAgAIAJAgQAMMHNSKEbbrghpnXHjx/3vGbKlCme18yfP9/zmqysLM9rJCkUCnle88UXX3he09jY2C/HGTIktv/GnDZtmuc1N954o+c1sdyMtLW11fOatLQ0z2skqaGhIaZ1uDJcAQEATBAgAIAJzwHat2+f5s+fr1AoJJ/Pp507d0Y9v2zZMvl8vqht3rx58ZoXADBIeA5QR0eH8vLyVF5e3uc+8+bNU1NTU2R74403rmpIAMDg4/lDCMXFxSouLv7affx+v4LBYMxDAQAGv4S8B1RZWanMzExNmjRJq1at0unTp/vct6urS+FwOGoDAAx+cQ/QvHnz9Nprr6miokK/+tWvVFVVpeLiYl24cKHX/cvKyhQIBCJbTk5OvEcCAAxAcf89oCVLlkT+eerUqZo2bZomTJigyspKzZkz55L9S0tLtW7dusjX4XCYCAHANSDhH8MeP368MjIyVFtb2+vzfr9fqampURsAYPBLeIBOnDih06dPKzs7O9GHAgAkEc9/BHfmzJmoq5n6+nodPnxY6enpSk9P14YNG7Ro0SIFg0HV1dXpySef1K233qqioqK4Dg4ASG6eA3Tw4EHde++9ka+/ev9m6dKl2rx5s44cOaI//OEPam1tVSgU0ty5c/Wzn/1Mfr8/flMDAJKezznnrIf4f+FwWIFAQG1tbbwf1E9effXVmNaVlJR4XtPZ2RnTsTDwxXLDz///0NKVyszM9Lzmhz/8oec1kvhAVIyu9Oc494IDAJggQAAAEwQIAGCCAAEATBAgAIAJAgQAMEGAAAAmCBAAwAQBAgCYIEAAABMECABgggABAEwQIACACe6GjZjV1dV5XtPX34z7dSoqKjyvaWlp8bymP3366aee1xw9etTzmgULFnheI0mrV6/2vGbu3LkxHQuDD3fDBgAMaAQIAGCCAAEATBAgAIAJAgQAMEGAAAAmCBAAwAQBAgCYIEAAABMECABgggABAEwQIACACW5GChh4+OGHPa/585//7HnNsWPHPK+RpIyMjJjWARI3IwUADHAECABgggABAEwQIACACQIEADBBgAAAJggQAMAEAQIAmCBAAAATBAgAYIIAAQBMECAAgIlh1gMA16K//OUvnteMGjXK8xpuKoqBjCsgAIAJAgQAMEGAAAAmCBAAwAQBAgCYIEAAABMECABgggABAEwQIACACQIEADBBgAAAJggQAMAENyMFrtIn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IEAAABNJE6Dy8nLdcsstuu6665Sfn69PPvnEeqR+99xzz8nn80VtkydPth4r4fbt26f58+crFArJ5/Np586dUc875/Tss88qOztbI0eOVGFhoY4fP24zbAJd7jwsW7bsktfHvHnzbIZNkLKyMs2YMUMpKSnKzMzUwoULVVNTE7VPZ2enSkpKNHr0aN1www1atGiRWlpajCZOjCs5D7Nnz77k9bBy5UqjiXuXFAF66623tG7dOq1fv16ffvqp8vLyVFRUpFOnTlmP1u/uuOMONTU1RbYPP/zQeqSE6+joUF5ensrLy3t9ftOmTXrppZf0yiuv6MCBA7r++utVVFSkzs7Ofp40sS53HiRp3rx5Ua+PN954ox8nTLyqqiqVlJRo//792rNnj86fP6+5c+eqo6Mjss/jjz+ud999V9u3b1dVVZVOnjyp+++/33Dq+LuS8yBJy5cvj3o9bNq0yWjiPrgkMHPmTFdSUhL5+sKFCy4UCrmysjLDqfrf+vXrXV5envUYpiS5HTt2RL7u7u52wWDQPf/885HHWltbnd/vd2+88YbBhP3j4vPgnHNLly51CxYsMJnHyqlTp5wkV1VV5Zzr+d9++PDhbvv27ZF9/va3vzlJrrq62mrMhLv4PDjn3He/+133ox/9yG6oKzDgr4DOnTunQ4cOqbCwMPLYkCFDVFhYqOrqasPJbBw/flyhUEjjx4/XQw89pIaGBuuRTNXX16u5uTnq9REIBJSfn39Nvj4qKyuVmZmpSZMmadWqVTp9+rT1SAnV1tYmSUpPT5ckHTp0SOfPn496PUyePFljx44d1K+Hi8/DV15//XVlZGRoypQpKi0t1dmzZy3G69OAuxnpxb744gtduHBBWVlZUY9nZWXp888/N5rKRn5+vrZu3apJkyapqalJGzZs0D333KOjR48qJSXFejwTzc3NktTr6+Or564V8+bN0/3336/c3FzV1dXppz/9qYqLi1VdXa2hQ4dajxd33d3dWrt2re666y5NmTJFUs/rYcSIEUpLS4vadzC/Hno7D5L04IMPaty4cQqFQjpy5Iieeuop1dTU6J133jGcNtqADxD+p7i4OPLP06ZNU35+vsaNG6e3335bjz76qOFkGAiWLFkS+eepU6dq2rRpmjBhgiorKzVnzhzDyRKjpKRER48evSbeB/06fZ2HFStWRP556tSpys7O1pw5c1RXV6cJEyb095i9GvB/BJeRkaGhQ4de8imWlpYWBYNBo6kGhrS0NE2cOFG1tbXWo5j56jXA6+NS48ePV0ZGxqB8faxZs0bvvfeePvjgg6i/viUYDOrcuXNqbW2N2n+wvh76Og+9yc/Pl6QB9XoY8AEaMWKEpk+froqKishj3d3dqqioUEFBgeFk9s6cOaO6ujplZ2dbj2ImNzdXwWAw6vURDod14MCBa/71ceLECZ0+fXpQvT6cc1qzZo127NihvXv3Kjc3N+r56dOna/jw4VGvh5qaGjU0NAyq18PlzkNvDh8+LEkD6/Vg/SmIK/Hmm286v9/vtm7d6o4dO+ZWrFjh0tLSXHNzs/Vo/erHP/6xq6ysdPX19e6jjz5yhYWFLiMjw506dcp6tIRqb293n332mfvss8+cJPfCCy+4zz77zP3jH/9wzjn3y1/+0qWlpbldu3a5I0eOuAULFrjc3Fz35ZdfGk8eX193Htrb290TTzzhqqurXX19vXv//ffdN7/5TXfbbbe5zs5O69HjZtWqVS4QCLjKykrX1NQU2c6ePRvZZ+XKlW7s2LFu79697uDBg66goMAVFBQYTh1/lzsPtbW1buPGje7gwYOuvr7e7dq1y40fP97NmjXLePJoSREg55x7+eWX3dixY92IESPczJkz3f79+61H6neLFy922dnZbsSIEe7mm292ixcvdrW1tdZjJdwHH3zgJF2yLV261DnX81HsZ555xmVlZTm/3+/mzJnjampqbIdOgK87D2fPnnVz5851N910kxs+fLgbN26cW758+aD7j7Te/v0luS1btkT2+fLLL93q1avdjTfe6EaNGuXuu+8+19TUZDd0AlzuPDQ0NLhZs2a59PR05/f73a233up+8pOfuLa2NtvBL8JfxwAAMDHg3wMCAAxOBAgAYIIAAQBMECAAgAkCBAAwQYAAACYIEADABAECAJggQAAAEwQIAGCCAAEATBAgAICJ/wIy88BDym5DhQAAAABJRU5ErkJggg=="
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ]
  },
  {
   "metadata": {
    "id": "lGyau0mOaP2m",
    "colab_type": "text"
   },
   "cell_type": "markdown",
   "source": [
    "### Defining The Neural Network"
   ]
  },
  {
   "metadata": {
    "id": "3WJXInzQGcAy",
    "colab_type": "code",
    "outputId": "be31aea8-542d-46ab-9816-85bc418664f9",
    "colab": {
     "base_uri": "https://localhost:8080/",
     "height": 153
    },
    "ExecuteTime": {
     "end_time": "2024-11-26T14:51:26.013522400Z",
     "start_time": "2024-11-26T14:51:25.992928800Z"
    }
   },
   "cell_type": "code",
   "source": [
    "class Net(nn.Module):\n",
    "    def __init__(self):\n",
    "        super(Net, self).__init__()\n",
    "        \n",
    "\n",
    "        self.conv_block1 = nn.Sequential(\n",
    "            nn.Conv2d(1, 32, kernel_size=3, stride=1, padding=1),\n",
    "            nn.BatchNorm2d(32),\n",
    "            nn.ReLU(inplace=True),\n",
    "            nn.Conv2d(32, 32, kernel_size=3, stride=1, padding=1),\n",
    "            nn.BatchNorm2d(32),\n",
    "            nn.ReLU(inplace=True),\n",
    "            nn.MaxPool2d(3, stride=2),\n",
    "        )\n",
    "    \n",
    "    \n",
    "        self.conv_block2 = nn.Sequential(\n",
    "            nn.Conv2d(32, 64, kernel_size=3, stride=1, padding=1),\n",
    "            nn.BatchNorm2d(64),\n",
    "            nn.ReLU(inplace=True),\n",
    "            nn.Conv2d(64, 64, kernel_size=3, stride=1, padding=1),\n",
    "            nn.BatchNorm2d(64),\n",
    "            nn.ReLU(inplace=True),\n",
    "            nn.MaxPool2d(3, stride=2),\n",
    "        )\n",
    "        \n",
    "          \n",
    "\n",
    "        self.fcs = nn.Sequential(\n",
    "            nn.Linear(2304, 1152),\n",
    "            nn.ReLU(inplace=True),\n",
    "            nn.Dropout(0.5),\n",
    "            nn.Linear(1152, 576),\n",
    "            nn.ReLU(inplace=True),\n",
    "            nn.Dropout(0.5),\n",
    "            nn.Linear(576, 10)\n",
    "        )\n",
    "\n",
    "    def forward(self, x):\n",
    "        x = self.conv_block1(x)\n",
    "        x = self.conv_block2(x)\n",
    "        x = x.reshape(x.shape[0], -1)\n",
    "        x = self.fcs(x)\n",
    "        return x\n",
    "    \n",
    " # 添加允许的全局变量\n",
    "torch.serialization.add_safe_globals([Net])\n",
    "              "
   ],
   "execution_count": 21,
   "outputs": []
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2024-11-26T14:51:26.440143300Z",
     "start_time": "2024-11-26T14:51:26.418545800Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": "Net(\n  (conv_block1): Sequential(\n    (0): Conv2d(1, 32, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))\n    (1): BatchNorm2d(32, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n    (2): ReLU(inplace=True)\n    (3): Conv2d(32, 32, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))\n    (4): BatchNorm2d(32, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n    (5): ReLU(inplace=True)\n    (6): MaxPool2d(kernel_size=3, stride=2, padding=0, dilation=1, ceil_mode=False)\n  )\n  (conv_block2): Sequential(\n    (0): Conv2d(32, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))\n    (1): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n    (2): ReLU(inplace=True)\n    (3): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))\n    (4): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n    (5): ReLU(inplace=True)\n    (6): MaxPool2d(kernel_size=3, stride=2, padding=0, dilation=1, ceil_mode=False)\n  )\n  (fcs): Sequential(\n    (0): Linear(in_features=2304, out_features=1152, bias=True)\n    (1): ReLU(inplace=True)\n    (2): Dropout(p=0.5, inplace=False)\n    (3): Linear(in_features=1152, out_features=576, bias=True)\n    (4): ReLU(inplace=True)\n    (5): Dropout(p=0.5, inplace=False)\n    (6): Linear(in_features=576, out_features=10, bias=True)\n  )\n)"
     },
     "execution_count": 22,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "model = Net()\n",
    "model"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2024-11-26T14:51:27.045537700Z",
     "start_time": "2024-11-26T14:51:27.035427700Z"
    }
   },
   "outputs": [],
   "source": [
    "optimizer = optim.Adam(params=model.parameters(), lr=0.001)\n",
    "criterion = nn.CrossEntropyLoss()\n",
    "\n",
    "exp_lr_scheduler = optim.lr_scheduler.StepLR(optimizer, step_size=7, gamma=0.1)\n",
    "\n",
    "if torch.cuda.is_available():\n",
    "    model = model.to(device)\n",
    "    criterion = criterion.to(device)"
   ]
  },
  {
   "metadata": {
    "id": "wstRGu4FaJBe",
    "colab_type": "text"
   },
   "cell_type": "markdown",
   "source": [
    "### Train and evaluate"
   ]
  },
  {
   "metadata": {
    "id": "XCsoAdjdLjPb",
    "colab_type": "code",
    "outputId": "6e7a5f80-f945-4e5c-c538-8ef445b6ad3e",
    "colab": {
     "base_uri": "https://localhost:8080/",
     "height": 306
    },
    "ExecuteTime": {
     "end_time": "2024-11-26T14:51:28.300394500Z",
     "start_time": "2024-11-26T14:51:28.277433100Z"
    }
   },
   "cell_type": "code",
   "source": [
    "def train_model(model, criterion, optimizer, scheduler, dataset_sizes, dataloaders, num_epochs=25 ):\n",
    "    since = time.time()\n",
    "\n",
    "    best_model_wts = copy.deepcopy(model.state_dict())\n",
    "    best_acc = 0.0\n",
    "\n",
    "    for epoch in range(num_epochs):\n",
    "        print('Epoch {}/{}'.format(epoch, num_epochs - 1))\n",
    "        print('-' * 10)\n",
    "\n",
    "        # Each epoch has a training and validation phase\n",
    "        for phase in ['train', 'val']:\n",
    "            if phase == 'train':\n",
    "                model.train()  # Set model to training mode\n",
    "            else:\n",
    "                model.eval()   # Set model to evaluate mode\n",
    "\n",
    "            running_loss = 0.0\n",
    "            running_corrects = 0\n",
    "\n",
    "            # Iterate over data.\n",
    "            for inputs, labels in dataloaders[phase]:\n",
    "                inputs = inputs.to(device)\n",
    "                labels = labels.to(device)\n",
    "\n",
    "                # zero the parameter gradients\n",
    "                optimizer.zero_grad()\n",
    "\n",
    "                # forward\n",
    "                # track history if only in train\n",
    "                with torch.set_grad_enabled(phase == 'train'):\n",
    "                    outputs = model(inputs)\n",
    "                    _, preds = torch.max(outputs, 1)\n",
    "                    loss = criterion(outputs, labels)\n",
    "\n",
    "                    # backward + optimize only if in training phase\n",
    "                    if phase == 'train':\n",
    "                        loss.backward()\n",
    "                        optimizer.step()\n",
    "\n",
    "                # statistics\n",
    "                running_loss += loss.item() * inputs.size(0)\n",
    "                running_corrects += torch.sum(preds == labels.data)\n",
    "            if phase == 'train':\n",
    "                scheduler.step()\n",
    "\n",
    "            epoch_loss = running_loss / dataset_sizes[phase]\n",
    "            epoch_acc = running_corrects.double() / dataset_sizes[phase]\n",
    "\n",
    "            print('{} Loss: {:.4f} Acc: {:.4f}'.format(\n",
    "                phase, epoch_loss, epoch_acc))\n",
    "\n",
    "            # deep copy the model\n",
    "            if phase == 'val' and epoch_acc > best_acc:\n",
    "                best_acc = epoch_acc\n",
    "                best_model_wts = copy.deepcopy(model.state_dict())\n",
    "\n",
    "        print()\n",
    "\n",
    "    time_elapsed = time.time() - since\n",
    "    print('Training complete in {:.0f}m {:.0f}s'.format(\n",
    "        time_elapsed // 60, time_elapsed % 60))\n",
    "    print('Best val Acc: {:4f}'.format(best_acc))\n",
    "\n",
    "    # load best model weights\n",
    "    model.load_state_dict(best_model_wts)\n",
    "    return model"
   ],
   "execution_count": 24,
   "outputs": []
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2024-11-26T14:54:31.473318700Z",
     "start_time": "2024-11-26T14:51:28.726972Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch 0/6\n",
      "----------\n",
      "train Loss: 0.1799 Acc: 0.9445\n",
      "val Loss: 0.0533 Acc: 0.9850\n",
      "\n",
      "Epoch 1/6\n",
      "----------\n",
      "train Loss: 0.0709 Acc: 0.9804\n",
      "val Loss: 0.0433 Acc: 0.9872\n",
      "\n",
      "Epoch 2/6\n",
      "----------\n",
      "train Loss: 0.0566 Acc: 0.9855\n",
      "val Loss: 0.0263 Acc: 0.9922\n",
      "\n",
      "Epoch 3/6\n",
      "----------\n",
      "train Loss: 0.0479 Acc: 0.9873\n",
      "val Loss: 0.0298 Acc: 0.9914\n",
      "\n",
      "Epoch 4/6\n",
      "----------\n",
      "train Loss: 0.0393 Acc: 0.9898\n",
      "val Loss: 0.0213 Acc: 0.9937\n",
      "\n",
      "Epoch 5/6\n",
      "----------\n",
      "train Loss: 0.0350 Acc: 0.9911\n",
      "val Loss: 0.0284 Acc: 0.9920\n",
      "\n",
      "Epoch 6/6\n",
      "----------\n",
      "train Loss: 0.0305 Acc: 0.9918\n",
      "val Loss: 0.0252 Acc: 0.9942\n",
      "\n",
      "Training complete in 3m 3s\n",
      "Best val Acc: 0.994200\n"
     ]
    }
   ],
   "source": [
    "model_ft = train_model(model, criterion, optimizer, exp_lr_scheduler,dataset_sizes,dataloaders,num_epochs=7)"
   ]
  },
  {
   "source": [
    "## Visualizing the model predictions"
   ],
   "cell_type": "markdown",
   "metadata": {}
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2024-11-26T14:54:31.493276400Z",
     "start_time": "2024-11-26T14:54:31.475318400Z"
    }
   },
   "outputs": [],
   "source": [
    "def imshow(inp, title=None):\n",
    "    \"\"\"Imshow for Tensor.\"\"\"\n",
    "    inp = inp.numpy().squeeze()\n",
    "    plt.imshow(inp, cmap='gray_r')\n",
    "    if title is not None:\n",
    "        plt.title(title)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2024-11-26T14:54:31.504279600Z",
     "start_time": "2024-11-26T14:54:31.491276Z"
    }
   },
   "outputs": [],
   "source": [
    "def visualize_model(model, num_images=6):\n",
    "    was_training = model.training\n",
    "    model.eval()\n",
    "    images_so_far = 0\n",
    "\n",
    "    with torch.no_grad():\n",
    "        for i, (inputs, labels) in enumerate(dataloaders['val']):\n",
    "            inputs = inputs.to(device)\n",
    "            labels = labels.to(device)\n",
    "\n",
    "            outputs = model(inputs)\n",
    "            _, preds = torch.max(outputs, 1)\n",
    "\n",
    "            for j in range(inputs.size()[0]):\n",
    "                images_so_far += 1\n",
    "                ax = plt.subplot(num_images//2, 2, images_so_far)\n",
    "                ax.axis('off')\n",
    "                ax.set_title('predicted: {}'.format(class_names[preds[j]]))\n",
    "\n",
    "                imshow(inputs.cpu().data[j])\n",
    "                if images_so_far == num_images:\n",
    "                    model.train(mode=was_training)\n",
    "                    plt.show()\n",
    "                    return\n",
    "        model.train(mode=was_training)\n"
   ]
  },
  {
   "metadata": {
    "id": "Ie9Fffl_Mqp6",
    "colab_type": "code",
    "outputId": "2e93c6ea-0534-498d-e072-904f62591dfe",
    "colab": {
     "base_uri": "https://localhost:8080/",
     "height": 261
    },
    "ExecuteTime": {
     "end_time": "2024-11-26T14:54:31.654911Z",
     "start_time": "2024-11-26T14:54:31.506279600Z"
    }
   },
   "cell_type": "code",
   "source": [
    "visualize_model(model)"
   ],
   "execution_count": 28,
   "outputs": [
    {
     "data": {
      "text/plain": "<Figure size 640x480 with 6 Axes>",
      "image/png": "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"
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2024-11-26T14:28:35.033420100Z",
     "start_time": "2024-11-26T14:28:35.015295700Z"
    }
   },
   "outputs": [],
   "source": [
    "torch.save(model, './my_mnist_model.pt') "
   ]
  },
  {
   "cell_type": "code",
   "outputs": [],
   "source": [
    "\n",
    "\n",
    "\n",
    "\n"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2024-11-26T14:33:05.333174700Z",
     "start_time": "2024-11-26T14:33:05.317444600Z"
    }
   },
   "execution_count": 15
  },
  {
   "cell_type": "code",
   "outputs": [
    {
     "ename": "UnpicklingError",
     "evalue": "Weights only load failed. This file can still be loaded, to do so you have two options \n\t(1) Re-running `torch.load` with `weights_only` set to `False` will likely succeed, but it can result in arbitrary code execution. Do it only if you got the file from a trusted source.\n\t(2) Alternatively, to load with `weights_only=True` please check the recommended steps in the following error message.\n\tWeightsUnpickler error: Unsupported global: GLOBAL __main__.Net was not an allowed global by default. Please use `torch.serialization.add_safe_globals([Net])` to allowlist this global if you trust this class/function.\n\nCheck the documentation of torch.load to learn more about types accepted by default with weights_only https://pytorch.org/docs/stable/generated/torch.load.html.",
     "output_type": "error",
     "traceback": [
      "\u001B[1;31m---------------------------------------------------------------------------\u001B[0m",
      "\u001B[1;31mUnpicklingError\u001B[0m                           Traceback (most recent call last)",
      "Cell \u001B[1;32mIn[20], line 25\u001B[0m\n\u001B[0;32m     23\u001B[0m \u001B[38;5;66;03m# 加载模型\u001B[39;00m\n\u001B[0;32m     24\u001B[0m model \u001B[38;5;241m=\u001B[39m Net()  \u001B[38;5;66;03m# 再次定义您的模型类\u001B[39;00m\n\u001B[1;32m---> 25\u001B[0m model\u001B[38;5;241m.\u001B[39mload_state_dict(\u001B[43mtorch\u001B[49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mload\u001B[49m\u001B[43m(\u001B[49m\u001B[43mmodel_path\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43mweights_only\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[38;5;28;43;01mTrue\u001B[39;49;00m\u001B[43m)\u001B[49m)\n\u001B[0;32m     26\u001B[0m model\u001B[38;5;241m.\u001B[39mto(device)  \u001B[38;5;66;03m# 将模型转移到指定设备\u001B[39;00m\n\u001B[0;32m     27\u001B[0m model\u001B[38;5;241m.\u001B[39meval()\n",
      "File \u001B[1;32mD:\\Documents\\Tool\\anaconda3\\envs\\Pytorch\\lib\\site-packages\\torch\\serialization.py:1096\u001B[0m, in \u001B[0;36mload\u001B[1;34m(f, map_location, pickle_module, weights_only, mmap, **pickle_load_args)\u001B[0m\n\u001B[0;32m   1090\u001B[0m                 \u001B[38;5;28;01mreturn\u001B[39;00m _load(opened_zipfile,\n\u001B[0;32m   1091\u001B[0m                              map_location,\n\u001B[0;32m   1092\u001B[0m                              _weights_only_unpickler,\n\u001B[0;32m   1093\u001B[0m                              overall_storage\u001B[38;5;241m=\u001B[39moverall_storage,\n\u001B[0;32m   1094\u001B[0m                              \u001B[38;5;241m*\u001B[39m\u001B[38;5;241m*\u001B[39mpickle_load_args)\n\u001B[0;32m   1095\u001B[0m             \u001B[38;5;28;01mexcept\u001B[39;00m \u001B[38;5;167;01mRuntimeError\u001B[39;00m \u001B[38;5;28;01mas\u001B[39;00m e:\n\u001B[1;32m-> 1096\u001B[0m                 \u001B[38;5;28;01mraise\u001B[39;00m pickle\u001B[38;5;241m.\u001B[39mUnpicklingError(_get_wo_message(\u001B[38;5;28mstr\u001B[39m(e))) \u001B[38;5;28;01mfrom\u001B[39;00m \u001B[38;5;28;01mNone\u001B[39;00m\n\u001B[0;32m   1097\u001B[0m         \u001B[38;5;28;01mreturn\u001B[39;00m _load(\n\u001B[0;32m   1098\u001B[0m             opened_zipfile,\n\u001B[0;32m   1099\u001B[0m             map_location,\n\u001B[1;32m   (...)\u001B[0m\n\u001B[0;32m   1102\u001B[0m             \u001B[38;5;241m*\u001B[39m\u001B[38;5;241m*\u001B[39mpickle_load_args,\n\u001B[0;32m   1103\u001B[0m         )\n\u001B[0;32m   1104\u001B[0m \u001B[38;5;28;01mif\u001B[39;00m mmap:\n",
      "\u001B[1;31mUnpicklingError\u001B[0m: Weights only load failed. This file can still be loaded, to do so you have two options \n\t(1) Re-running `torch.load` with `weights_only` set to `False` will likely succeed, but it can result in arbitrary code execution. Do it only if you got the file from a trusted source.\n\t(2) Alternatively, to load with `weights_only=True` please check the recommended steps in the following error message.\n\tWeightsUnpickler error: Unsupported global: GLOBAL __main__.Net was not an allowed global by default. Please use `torch.serialization.add_safe_globals([Net])` to allowlist this global if you trust this class/function.\n\nCheck the documentation of torch.load to learn more about types accepted by default with weights_only https://pytorch.org/docs/stable/generated/torch.load.html."
     ]
    }
   ],
   "source": [],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2024-11-26T14:34:24.887468Z",
     "start_time": "2024-11-26T14:34:24.841777Z"
    }
   },
   "execution_count": 20
  },
  {
   "cell_type": "code",
   "outputs": [],
   "source": [],
   "metadata": {
    "collapsed": false
   }
  }
 ]
}
